/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package data;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Agnieszka
 */
public class Tool {

    public static BigInteger blind(BigInteger m, BigInteger e, BigInteger n, BigInteger r) {
        System.out.println("\nbefore = " + String.valueOf(m));
        BigInteger b = ((r.modPow(e, n)).multiply(m)).mod(n);
        System.out.println("\nb = " + b);
        return b;
    }

    public static String blind(String m, BigInteger e, BigInteger n, BigInteger r) throws UnsupportedEncodingException {
        return String.valueOf(blind(new BigInteger(m.getBytes("UTF8")), e, n, r));
    }

    public static BigInteger sign(BigInteger b, BigInteger d, BigInteger n) {
        System.out.println("\nbefore = " + String.valueOf(b));
        BigInteger bs = b.modPow(d, n);
        System.out.println("bs = " + bs);
        return bs;
    }

    public static String sign(String b, BigInteger d, BigInteger n) throws UnsupportedEncodingException {
        return String.valueOf(sign(new BigInteger(b.getBytes("UTF8")), d, n));
    }

    public static BigInteger unblind(BigInteger bs, BigInteger n, BigInteger r) {
        System.out.println("\nbefore = " + String.valueOf(bs));
        BigInteger s = r.modInverse(n).multiply(bs).mod(n);
        System.out.println("s = " + s);
        return s;
    }

    public static String unblind(String bs, BigInteger n, BigInteger r) throws UnsupportedEncodingException {
        return String.valueOf(unblind(new BigInteger(bs.getBytes("UTF8")), n, r));
    }
    
    public static BigInteger unblindToClean(BigInteger b, BigInteger e, BigInteger n, BigInteger r) {
        System.out.println("\nbefore = " + String.valueOf(b));
        BigInteger s = r.modPow(e.multiply(BigInteger.valueOf(-1)), n).multiply(b).mod(n);
        System.out.println("clean = " + s);
        return s;
    }

    public static String unblindToClean(String b, BigInteger e, BigInteger n, BigInteger r) throws UnsupportedEncodingException {
        return String.valueOf(unblindToClean(new BigInteger(b.getBytes("UTF8")), e, n, r));
    }

    public static BigInteger signToClean(BigInteger s, BigInteger e, BigInteger n) {
        System.out.println("\nbefore = " + String.valueOf(s));
        BigInteger c = s.modPow(e, n);
        System.out.println("clean = " + c);
        return s;
    }

    public static String signToClean(String s, BigInteger e, BigInteger n) throws UnsupportedEncodingException {
        return String.valueOf(signToClean(new BigInteger(s.getBytes("UTF8")), e, n));
    }
    
    public static Boolean verify(BigInteger s, BigInteger m, BigInteger d, BigInteger n) {
        System.out.println("\nbefore s = " + String.valueOf(s));
        System.out.println("\nbefore m = " + String.valueOf(m));

        //signature of m should = (m^d) mod n
        BigInteger sig_of_m = m.modPow(d, n);
        System.out.println("sig_of_m = " + sig_of_m);

        //check that s is equal to a signature of m:
        Boolean v = s.equals(sig_of_m);
        System.out.println(v);
        System.out.println("s " + String.valueOf(s));
        System.out.println("sign_of_m " + String.valueOf(sig_of_m));

        return v;
    }

    public static String verify(String s, String m, BigInteger d, BigInteger n) throws UnsupportedEncodingException {
        return String.valueOf(verify(new BigInteger(s.getBytes("UTF8")), new BigInteger(m.getBytes("UTF8")), d, n));
    }

    public static Boolean verifyByRSA(BigInteger s, BigInteger m, BigInteger e, BigInteger n) {

        //try to verify using the RSA formula
        BigInteger check = s.modPow(e, n);

        Boolean v = m.equals(check);
        System.out.println(v);

        System.out.println("check " + new String(check.toByteArray()));
        System.out.println("m " + new String(m.toByteArray()));

        return v;
    }

    public static String verifyByRSA(String s, String m, BigInteger e, BigInteger n) throws UnsupportedEncodingException {
        return String.valueOf(verifyByRSA(new BigInteger(s.getBytes("UTF8")), new BigInteger(m.getBytes("UTF8")), e, n));
    }

    public static BigInteger r(BigInteger n) {
        try {
            SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
            byte[] randomBytes = new byte[10];
            BigInteger r = null;
            BigInteger gcd = null;
            BigInteger one = new BigInteger("1");
            //check that gcd(r,n) = 1 && r < n && r > 1
            do {
                random.nextBytes(randomBytes);
                r = new BigInteger(1, randomBytes);
                gcd = r.gcd(n);
                System.out.println("gcd: " + gcd);
            } while (!gcd.equals(one) || r.compareTo(n) >= 0 || r.compareTo(one) <= 0);

            return r;
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Tool.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchProviderException ex) {
            Logger.getLogger(Tool.class.getName()).log(Level.SEVERE, null, ex);
        }

        return null;

    }

    public static BigInteger nextSerialNumber(SecureRandom random) throws UnsupportedEncodingException {
        return new BigInteger(new BigInteger(7, random).toString().getBytes("UTF8"));

        //return new BigInteger("3456");
    }
}
